package pishen;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.apache.commons.collections15.Factory;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Pair;

// high Assortativity
public class AssortativityGenerator<V,E> {
	private Graph<V,E> graph;
    private Factory<E> edgeFactory;
	private int mNumIterations;
    private Random mRandom;
    
    // constructor
	public AssortativityGenerator(Graph<V, E> g , Factory<E> edgeFactory, int r){
		this.graph = g;
	    this.edgeFactory = edgeFactory;
		this.mNumIterations = r;
	    this.mRandom = new Random();
	}
	
	// main algorithm
	public Graph<V, E> run(){
		for(int rIdx = 0; rIdx < mNumIterations; rIdx++){
			// 
            List<E> edges = new ArrayList<E>(graph.getEdges());
            E e1 = edges.get((int)(mRandom.nextDouble() * graph.getEdgeCount()));
           	E e2 = edges.get((int)(mRandom.nextDouble() * graph.getEdgeCount()));
            
            //
           	Pair<V> p1 = graph.getEndpoints(e1);
            Pair<V> p2 = graph.getEndpoints(e2);
            V v1 = p1.getFirst();
            V v2 = p1.getSecond();
            V v3 = p2.getFirst();
            V v4 = p2.getSecond();
            
            //
            int d1 = graph.degree(v1);
            int d2 = graph.degree(v2);
            int d3 = graph.degree(v3);
            int d4 = graph.degree(v4);
            
            //
            int num1 = (d1-d2)*(d1-d2) + (d3-d4)*(d3-d4);
            int num2 = (d1-d3)*(d1-d3) + (d2-d4)*(d2-d4);
            int num3 = (d1-d4)*(d1-d4) + (d2-d3)*(d2-d3);
           
            if( (num2 < num1) && (num2 <= num3) ){
               	//
            	//graph.removeEdge(e1);
            	//graph.removeEdge(e2);
            	graph.addEdge(edgeFactory.create(), v1, v3);
            	graph.addEdge(edgeFactory.create(), v2, v4);
         
            }else if( (num3 < num1) && (num3 < num2) ){
            	//
            	//graph.removeEdge(e1);
            	//graph.removeEdge(e2);
            	graph.addEdge(edgeFactory.create(), v1, v4);
            	graph.addEdge(edgeFactory.create(), v2, v3);
            }
		}
		return graph;
	}
}